package com.marco.dao.common;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.marco.dao.common.pager.Pageable;
import com.marco.dao.common.query.Filter;
import com.marco.dao.common.query.QueryBuilder;
import com.marco.dao.common.query.UpdateBuilder;
import com.marco.dao.common.wrapper.IEntityWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author zixiaojun
 * @Description
 * @Date 2021/3/3 3:36 下午
 */
@Slf4j
public abstract class CURDCommonDao<M extends BaseMapper<T>, T> extends BaseDaoSupport<M,T>  {

    /**
     * 随机记录种子数
     */
    private final static Integer RAND_SEED_NUMBER = 20;

    public T insertEntity(UpdateBuilder<T> updateBuilder) {
        T entity = updateBuilder.getEntity();
        if (entity == null) {
            return null;
        }
        this.save(entity);
        return entity;
    }

    public T insertEntity0(T entity) {
        UpdateBuilder<T> updateBuilder=new UpdateBuilder<>(entity);
        return insertEntity(updateBuilder);
    }

    
    public boolean insertEntities(List<T> entities){
        return this.saveBatch(entities);
    }

    
    public boolean insertEntities(List<T> entities,Integer flushSize){
        return this.saveBatch(entities,flushSize);
    }

    
    public boolean updateEntity(UpdateBuilder<T> updateBuilder) {
        if(CollectionUtils.isEmpty(updateBuilder.getFilters())){
            throw new IllegalArgumentException("sql where parameter is null");
        }
        T updateEntity = updateBuilder.getEntity();
        IEntityWrapper wrapper = this.getWrapper(updateBuilder);
        wrapper.setEntity(null);
        if (updateEntity == null) {
            throw new IllegalArgumentException("sql set is null");
        }
        return this.update(updateEntity, wrapper);
    }


    public T selectEntity(QueryBuilder queryBuilder) {
    /*if(CollectionUtils.isEmpty(queryBuilder.getFilters())&&queryBuilder.getEntity()==null){
      throw new IllegalArgumentException("sql where is null");
    }*/
        IEntityWrapper wrapper = this.getWrapper(queryBuilder);
        List<T> entities = this.list(wrapper);
        return entities != null&&entities.size()>0 ? entities.get(0) : null;
    }

    public T selectEntity0(T entity) {
        QueryBuilder<T> queryBuilder = new QueryBuilder<T>(entity);
        Object obj = selectEntity(queryBuilder);
        return obj != null ? (T) obj : null;
    }

    public List<T> selectEntities(QueryBuilder queryBuilder) {
        IEntityWrapper wrapper = this.getWrapper(queryBuilder);
        List<T> entities = this.list(wrapper);
        return entities;
    }


    public List<T> selectEntities0(T entity) {
        QueryBuilder<T> queryBuilder = new QueryBuilder<T>(entity);
        return selectEntities(queryBuilder);
    }

    public Pageable<T> selectEntitiesByPage(QueryBuilder queryBuilder, Integer pageNum, Integer pageSize) {
        IEntityWrapper wrapper = this.getWrapper(queryBuilder);
        Pageable pageable = new Pageable(pageNum,pageSize);
        IPage<T> page = this.page(pageable, wrapper);
        return pageable.convertPage(page);
    }


    public Pageable<T> selectEntitiesByPage0(T entity, Integer pageNum, Integer pageSize) {
        return selectEntitiesByPage(new QueryBuilder<T>(entity),pageNum,pageSize);
    }

    public Integer count(QueryBuilder queryBuilder) {
        IEntityWrapper wrapper = this.getWrapper(queryBuilder);
        return this.count(wrapper);
    }

    public Integer count0(T entity) {
        return count(new QueryBuilder(entity));
    }


    public List<T> selectEntitiesByRandom(QueryBuilder queryBuilder, Integer size) {
        return selectEntitiesByRandom(queryBuilder,size,RAND_SEED_NUMBER);
    }

    public List<T> selectEntitiesByRandom(QueryBuilder queryBuilder, Integer size,Integer seed) {
        Integer count = count(queryBuilder);
        Integer limitRange = count > seed ? count - seed : 0;
        Integer limitRandStart = RandomUtils.nextInt(0, limitRange + 1);
        queryBuilder.addFilter(Filter.limit(limitRandStart,seed));
        IEntityWrapper wrapper = this.getWrapper(queryBuilder);
        List<T> seedList = this.list(wrapper);
        return getRandomListFromSeeds(seedList,size);
    }

    public List<T> selectEntitiesByRandom0(T entity, Integer size){
        return selectEntitiesByRandom(new QueryBuilder(entity),size,RAND_SEED_NUMBER);
    }

    public List<T> selectEntitiesByRandom0(T entity, Integer size,Integer seed){
        return selectEntitiesByRandom(new QueryBuilder(entity),size,seed);
    }

    private List<T> getRandomListFromSeeds(List<T> seedList, Integer size) {
        List<T> resultList = new ArrayList<>();
        if (CollectionUtils.isEmpty(seedList) && size <= 0) {
            return resultList;
        }
        Integer rangeNum = seedList.size();
        if (rangeNum <= size) {
            return seedList;
        }
        for (int i = 0; i < size; i++) {
            Integer index = RandomUtils.nextInt(0, rangeNum);
            if(index<=rangeNum){
                T entity=seedList.get(index);
                resultList.add(entity);
                seedList.remove(entity);
                rangeNum=seedList.size();
            }
        }
        return resultList;
    }

    
    public boolean deleteById(Long id){
        if(id.intValue() > 0){
            return this.removeById(id);
        }
        return false;
    }
}
